﻿using Edu.Abstracts;
using Edu.Contracts;
using Edu.Entitys;
using Edu.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Identity;
using Volo.Abp.Linq;
namespace Edu.Services
{
    public class StudentUserInfoDto
    {
        public Guid TeacherId { get; set; }
        public string TeacherAvatar { get; set; }

        public string TeacherName { get; set; }

        public string StartStudyTime { get; set; }
        public int Rank { get; set; }
        public int AchievementCount { get; set; }

        public JobType Job { get; set; }
        public Dictionary<AbilityType, int> Abilitys { get; set; }
    }


    public class StudentInfoDto
    {
        public Guid StudentId { get; set; }
        public StudentStatus Status { get; internal set; }
        public int? Score { get; internal set; }
        public int Rating { get; internal set; }
        public DateTimeOffset StartStudyTime { get; internal set; }
        public string Name { get; internal set; }
        public string Area { get; internal set; }
        public DateTimeOffset? GradTime { get; internal set; }
        public string Avatar { get; internal set; }
        public int AchievementCount { get; set; }

        public int Rank { get; set; }

        public int CompleteTaskCount { get; set; }
        public int UnCompleteTaskCount { get; set; }
        public int UnScoreCount { get; set; }
        public IReadOnlyList<StudyTaskDto> Tasks { get; set; }

        public string TeacherName { get; set; }

        public string TeacherAvatar { get; set; }

        public string TaskProgress { get; set; }
        public int PendingCount { get; set; }
        public Dictionary<AbilityType, int> Abilitys { get; set; }
        public JobType Job { get; set; }
    }


    public class AuditDto
    {
        public Guid StudentId { get; set; }
        public string StudentName { get; set; }

        public string StudentAvatar { get; set; }

        public Guid TeacherId { get; set; }
        public string TeacherName { get; set; }

        public string TeacherAvatar { get; set; }

        public IReadOnlyList<StudyTaskDto> Tasks { get; set; }

    }


    public class StudentAppService : WeChatAppServiceBase
    {
        public IRepository<AppStudent, Guid> Repository { get; }

        private IAppUserRepository appUsers;
        private IdentityUserManager userManager;

        public DefaultAsyncQueryableExecuter AsyncQueryableExecuter { get; }

        private StudyTaskAppService taskAppService;
        private UserAchievementAppService userAchievementAppService;
        private RankAppService rankAppService;

        public StudentAppService(IRepository<AppStudent, Guid> appStudents,
            IAppUserRepository appUsers,
        IdentityUserManager userManager,
        StudyTaskAppService taskAppService,
        UserAchievementAppService userAchievementAppService,
        RankAppService rankAppService
            )
        {
            AsyncQueryableExecuter = DefaultAsyncQueryableExecuter.Instance;
            this.Repository = appStudents;
            this.appUsers = appUsers;
            this.userManager = userManager;

            this.taskAppService = taskAppService;
            this.userAchievementAppService = userAchievementAppService;
            this.rankAppService = rankAppService;
        }


        public async Task<StudentUserInfoDto> GetStudentInfo()
        {
            var studentInfo = this.Repository.Single(a => a.UserId == this.CurrentUser.Id.Value);
            var teacherInfo = await appUsers.GetAsync(studentInfo.TeacherId);
            return new StudentUserInfoDto()
            {
                TeacherId = teacherInfo.Id,
                TeacherAvatar = teacherInfo.Avatar,
                TeacherName = teacherInfo.Name,
                StartStudyTime = studentInfo.StartStudyTime.ToString("yyyy-MM-dd"),
                AchievementCount = this.userAchievementAppService.GetAchievementCount(this.CurrentUser.Id.Value),
                Rank = studentInfo.Status == StudentStatus.Grad ? (int)rankAppService.GetStudentRankNum(this.CurrentUser.Id.Value, studentInfo.Job) : 0,
                Job = studentInfo.Job,
                Abilitys = taskAppService.GetStudentAbilitys(studentInfo.UserId)
            };
        }



        public async Task<PagedResultDto<StudentInfoDto>> GetListGradByTeacherAsync(Guid teacherId, PagedAndSortedResultRequestDto input)
        {
            var query = this.Repository.WithDetails(a => a.User);
            query = query.OrderBy(m => m.JoinYear).ThenBy(m => m.JoinQuarter);
            query = query.Where(a => a.TeacherId == teacherId && a.Status == StudentStatus.Grad);


            var totalCount = await AsyncQueryableExecuter.CountAsync(query);


            query = query.ApplySorting(input);
            query = query.ApplyPaging(input);
            var entities = await AsyncQueryableExecuter.ToListAsync(query);

            var result = new List<StudentInfoDto>();
            foreach (var item in entities)
            {
                result.Add(new StudentInfoDto
                {
                    StudentId = item.UserId,
                    Score = item.AssessScore,
                    GradTime = item.GradTime,
                    Rating = item.Rating,
                    StartStudyTime = item.StartStudyTime,
                    Status = item.Status,
                    Avatar = item.User.Avatar,
                    Name = item.User.Name,
                    Rank = (int)rankAppService.GetStudentRankNum(item.UserId,item.Job),
                    AchievementCount = this.userAchievementAppService.GetAchievementCount(item.UserId),
                    Job = item.Job,
                    Abilitys = taskAppService.GetStudentAbilitys(item.UserId)
                });
            }
            return new PagedResultDto<StudentInfoDto>(
                totalCount,
                result
            );
        }

        public async Task<List<StudentInfoDto>> GetListUnGradByTeacherAsync(Guid teacherId)
        {
            var query = this.Repository.WithDetails(a => a.User);
            query = query.OrderBy(m => m.JoinYear).ThenBy(m => m.JoinQuarter);
            query = query.Where(a => a.TeacherId == teacherId && (a.Status == StudentStatus.UnGrad || a.Status == StudentStatus.Delay));
            var entities = await AsyncQueryableExecuter.ToListAsync(query);
            return await Mapp(entities);
        }

        private async Task<List<StudentInfoDto>> Mapp(List<AppStudent> entities)
        {
            var result = new List<StudentInfoDto>();
            foreach (var item in entities)
            {
                var date = DateTimeOffset.UtcNow;
                var taskPageReust = await this.taskAppService.GetTasksAsync(item.UserId, date.Year, date.GetQuarter(), new PagedAndSortedResultRequestDto());

                var completeCount = 0;
                var unCompleteCount = 0;
                var unScoreCount = 0;
                var pendingCount = 0;

                foreach (var task in taskPageReust.Items)
                {
                    if (task.Status == StudyTaskStatus.Complete)
                    {
                        completeCount++;
                    }
                    else if (StudyTaskStatusIf.UnComplete(task.Status))
                    {
                        unCompleteCount++;
                    }
                    else if (task.Status == StudyTaskStatus.UnScore)
                    {
                        unScoreCount++;
                    }
                    else if (task.Status == StudyTaskStatus.Pending)
                    {
                        pendingCount++;
                    }
                }

                result.Add(new StudentInfoDto
                {
                    StudentId = item.UserId,
                    Score = item.AssessScore,
                    GradTime = item.GradTime,
                    Rating = item.Rating,
                    StartStudyTime = item.StartStudyTime,
                    Status = item.Status,
                    Avatar = item.User.Avatar,
                    Name = item.User.Name,
                    AchievementCount = this.userAchievementAppService.GetAchievementCount(item.UserId),
                    Tasks = taskPageReust.Items,
                    CompleteTaskCount = completeCount,
                    UnCompleteTaskCount = unCompleteCount,
                    UnScoreCount = unScoreCount,
                    PendingCount = pendingCount,
                    Job = item.Job,
                    Abilitys = taskAppService.GetStudentAbilitys(item.UserId)
                });
            }
            return result;
        }

        public async Task<PagedResultDto<AuditDto>> GetAuditList(PagedAndSortedResultRequestDto input)
        {

            input.MaxResultCount = 100000;
            var query = this.Repository.WithDetails(a => a.User);


            var currentAppUser = await this.appUsers.GetAsync(this.CurrentUser.Id.Value);

            var roles = await userManager.GetRolesAsync(MapToIdentityUser(currentAppUser));


            if (roles.IndexOf("admin-area") != -1)
            {
                query = query.Where(a => a.Status != StudentStatus.Grad && a.User.Area == currentAppUser.Area);
            }
            else
            {
                query = query.Where(a => a.Status != StudentStatus.Grad);
            }

            var totalCount = await AsyncQueryableExecuter.CountAsync(query);

            query = query.ApplyPaging(input);

            query = query.OrderBy(m => m.JoinYear).ThenBy(m => m.JoinQuarter);

            var entities = await AsyncQueryableExecuter.ToListAsync(query);

            var result = new List<AuditDto>();
            foreach (var item in entities)
            {
                var teacherInfo = await appUsers.GetAsync(item.TeacherId);

                var tasks = await taskAppService.GetPendingTasksAsync(item.UserId);
                result.Add(new AuditDto
                {
                    StudentId = item.User.Id,
                    StudentAvatar = item.User.Avatar,
                    StudentName = item.User.Name,
                    TeacherId = teacherInfo.Id,
                    TeacherAvatar = teacherInfo.Avatar,
                    TeacherName = teacherInfo.Name,
                    Tasks = tasks,
                });
            }
            return new PagedResultDto<AuditDto>(
                totalCount,
                result
            );
        }

        public async Task<PagedResultDto<StudentInfoDto>> GetListByAdminAsync(bool isGrad, PagedAndSortedResultRequestDto input)
        {
            input.MaxResultCount = 100000;
            var query = this.Repository.WithDetails(a => a.User);
            var currentAppUser = await this.appUsers.GetAsync(this.CurrentUser.Id.Value);
            var roles = await userManager.GetRolesAsync(MapToIdentityUser(currentAppUser));

            //if (isGrad == true)
            //{
            //    if (roles.IndexOf("admin-area") != -1)
            //    {
            //        query = query.Where(a => a.Status == StudentStatus.Grad && a.User.Area == currentAppUser.Area);
            //    }
            //    else
            //    {
            //        query = query.Where(a => a.Status == StudentStatus.Grad);
            //    }
            //}
            //else
            //{
            //    if (roles.IndexOf("admin-area") != -1)
            //    {
            //        query = query.Where(a => a.Status != StudentStatus.Grad && a.User.Area == currentAppUser.Area);
            //    }
            //    else
            //    {
            //        query = query.Where(a => a.Status != StudentStatus.Grad);
            //    }
            //}

            if (roles.IndexOf("admin-area") != -1)
            {
                query = query.Where(a => a.User.Area == currentAppUser.Area);
            }

            var totalCount = await AsyncQueryableExecuter.CountAsync(query);

            query = query.ApplyPaging(input);

            query = query.OrderBy(m => m.JoinYear).ThenBy(m => m.JoinQuarter);

            var entities = await AsyncQueryableExecuter.ToListAsync(query);

            var result = new List<StudentInfoDto>();

            var now = DateTimeOffset.UtcNow;
            var year = now.Year;
            var quarter = now.GetQuarter();

            foreach (var item in entities)
            {
                try
                {
                    var teacherId = item.TeacherId;

                    string teacherName = "";
                    string teacherAvatar = "";
                    string taskProgress = "";

                    var teacherInfo = await appUsers.GetAsync(teacherId);
                    //获取teacherinfo
                    teacherName = teacherInfo.Name;
                    teacherAvatar = teacherInfo.Avatar;
                    //获取任务进度
                    taskProgress = await taskAppService.GetTaskProgress(item.UserId, year, quarter);

                    result.Add(new StudentInfoDto
                    {
                        StudentId = item.UserId,
                        Score = item.AssessScore,
                        GradTime = item.GradTime,
                        Rating = item.Rating,
                        StartStudyTime = item.StartStudyTime,
                        Status = item.Status,
                        Area = EduConsts.AreaData[item.User.Area],
                        Avatar = item.User.Avatar,
                        Name = item.User.Name,
                        TeacherAvatar = teacherAvatar,
                        TeacherName = teacherName,
                        TaskProgress = taskProgress,
                        Job = item.Job
                    });
                }
                catch (Exception)
                {
                }

            }
            return new PagedResultDto<StudentInfoDto>(
                 totalCount,
                 result
            );
        }

    }
}
